package com.fagertveit.chainsawrus;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import com.fagertveit.chainsawrus.graphics.Graphics;
import com.fagertveit.chainsawrus.io.FileIO;
import com.fagertveit.chainsawrus.io.GameFileIO;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.Window;
import android.view.WindowManager;

public abstract class BasicGame extends Activity implements Game, Renderer {
	enum GameState {
		Initialized,
		Running,
		Paused,
		Finished,
		Idle
	}
	
	int width;
	int height;
	GLSurfaceView glView;
	Graphics graphics;
	FileIO fileIO;
	State state;
	GameState gameState = GameState.Initialized;
	Object stateChanged = new Object();
	long startTime = System.nanoTime();
	WakeLock wakeLock;
	
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		glView = new GLESView(this);
		glView.setRenderer(this);
		setContentView(glView);
		
		fileIO = new GameFileIO(getAssets());
		graphics = new Graphics(glView);
		PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
		wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GLGame");
	}
	public void onResume() {
		super.onResume();
		glView.onResume();
		wakeLock.acquire();
	}
	
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		
		synchronized(stateChanged) {
			if(gameState == GameState.Initialized) {
				state = getStartState();
			}
			gameState = GameState.Running;
			state.resume();
			startTime = System.nanoTime();
		}
	}
	
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		this.width = width;
		this.height = height;
	}
	
	public void onDrawFrame(GL10 gl) {
		GameState gameState = null;
		synchronized(stateChanged) {
			gameState = this.gameState;
		}
		
		if(gameState == GameState.Running) {
			long delta = (System.nanoTime() - startTime);
			startTime = System.nanoTime();
			
			state.update(delta);
			state.render(this.graphics, delta);
		}
		
		if(gameState == GameState.Paused) {
			state.pause();
			synchronized(stateChanged) {
				this.gameState = GameState.Idle;
				stateChanged.notifyAll();
			}
		}
		
		if(gameState == GameState.Finished) {
			state.pause();
			state.dispose();
			synchronized(stateChanged) {
				this.gameState = GameState.Idle;
				stateChanged.notifyAll();
			}
		}
	}
	
	public void onPause() {
		synchronized(stateChanged) {
			if(isFinishing()) {
				gameState = GameState.Finished;
			} else {
				gameState = GameState.Paused;
			}
			while(true) {
				try {
					stateChanged.wait();
					break;
				} catch(InterruptedException e) {
					
				}
			}
		}
		wakeLock.release();
		glView.onPause();
		super.onPause();
	}
	
	public Graphics getGraphics() {
		return graphics;
	}
	
	public FileIO getFileIO() {
		return fileIO;
	}
	
	public int getWidth() {
		return width;
	}
	
	public int getHeight() {
		return height;
	}
	
	public void setState(State state) {
		if(state == null) {
			throw new IllegalArgumentException("Screen must not be null!");
		}
		
		this.state.pause();
		this.state.dispose();
		state.resume();
		state.update(0);
		this.state = state;
	}
	
	public State getCurrentState() {
		return state;
	}
}
